<<<<<<< HEAD
library(ChromCom)
library(ggplot2)
library(gridExtra)
library(reshape2)
=======
library(mylib)
library(ChromCom)
library(ggplot2)
library(gridExtra)
library(reshape2)
library(parallel)
binDir <- "../RData"
>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

11/07/2017

Writing introduction. First script to do simulation.

12/07/2017

Let’s try if it works. An example for \(t_1 = -60\) min, \(\Delta t = 0\), \(k_1 = 0.04\ {\rm min}^{-1}\) and \(k_2 = 0.04\ {\rm min}^{-1}\).

<<<<<<< HEAD
pars <- list(
  t1 = -60,
  dt = 0,
  r1 = 0.04,
  r2 = 0.04
=======

pars <- c3pars(
  t1 = -60,
  dt2 = 0,
  k1 = 0.04,
  k2 = 0.04
>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba
)
chr <- ChromCom3(pars)
chr <- generateCells(chr, nsim=1000)
plotTimelines(chr)
<<<<<<< HEAD

=======

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

Just to check if output is as expected. With \(k_2=0\) we should have pure exponential decay. The yellow curve is \(e^{-k_1 t}\).

<<<<<<< HEAD
pars <- list(
  t1 = -60,
  dt = 0,
  r1 = 0.04,
  r2 = 0
=======

pars <- c3pars(
  t1 = -60,
  dt2 = 0,
  k1 = 0.04,
  k2 = 0
>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba
)
tchr <- ChromCom3(pars)
tchr <- generateCells(tchr, nsim=1000)
x <- seq(from=pars$t1, to=100, by=1)
<<<<<<< HEAD
y <- exp(-pars$r1 * (x - pars$t1))
=======
y <- exp(-pars$k1 * (x - pars$t1))
>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba
g <- plotTimelines(tchr)
g + geom_line(data=data.frame(x=x, y=y), aes(x,y), colour="yellow")
<<<<<<< HEAD

=======

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

Close, but not perfect. Here is an example with much smaller time step (0.1) and larger number of cells (10,000).

<<<<<<< HEAD
pars <- list(
  t1 = -60,
  dt = 0,
  r1 = 0.04,
  r2 = 0
=======

pars <- c3pars(
  t1 = -60,
  dt2 = 0,
  k1 = 0.04,
  k2 = 0
>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba
)
tchr <- ChromCom3(pars, time = seq(from=-140, to=90, by=0.1))
tchr <- generateCells(tchr, nsim=10000)
x <- seq(from=pars$t1, to=100, by=1)
<<<<<<< HEAD
y <- exp(-pars$r1 * (x - pars$t1))
=======
y <- exp(-pars$k1 * (x - pars$t1))
>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba
g <- plotTimelines(tchr)
g + geom_line(data=data.frame(x=x, y=y), aes(x,y), colour="yellow")
<<<<<<< HEAD

=======

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

Parameter grid

parameterGrid <- function(pars, par1, range1, par2, range2) {
  melts <- NULL
  for(p1 in range1) {
    pars[[par1]] <- p1
    for(p2 in range2) {
      pars[[par2]] <- p2
      chr <- ChromCom3(pars)
      chr <- generateCells(chr)
      label1 <- sprintf("%s = %.3g", par1, p1)
      label2 <- sprintf("%s = %.3g", par2, p2)
      m <- meltTimelines(chr, label1=label1, label2=label2)
      melts <- rbind(melts, m)
    }
  }
  timelinePanel(melts)
}
pars <- c3pars(
  t1 = -30,
  dt2 = 0,
  k1 = 0.05,
  k2 = 0.01
)
range1 <- c(0.01, 0.05, 0.08, 0.12)
range2 <- c(0.01, 0.05, 0.08, 0.12)
parameterGrid(pars, "k1", range1, "k2", range2)
<<<<<<< HEAD

=======

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

I think we need to introduce a delay between pink and red.

pars <- c3pars(
  t1 = -30,
  dt2 = 10,
  k1 = 0.05,
  k2 = 0.01
)
range1 <- c(0.01, 0.03, 0.05, 0.10)
range2 <- c(0.01, 0.05, 0.08, 0.12)
parameterGrid(pars, "k1", range1, "k2", range2)
<<<<<<< HEAD

=======

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

What about range of delays?

pars <- c3pars(
  t1 = -30,
  dt2 = 0,
  k1 = 0.03,
  k2 = 0.01
)
range1 <- c(0, 10, 20, 30)
range2 <- c(0.01, 0.05, 0.08, 0.12)
parameterGrid(pars, "dt", range1, "k2", range2)
<<<<<<< HEAD

=======

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

Experimental data.

echr <- experimentalData(dataFile$scramble)
plotTimelines(echr, smooth=TRUE, k=15)
<<<<<<< HEAD

=======

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

13/07/2017

Prepared shiny app for deployment.

24/07/2017

Tomo suggested that the model parameters can be derived directly from data. We can write the following equations

\(\dot{B} = -k_1 B\)

\(\dot{P} = k_1 B - k_2 R\)

\(\dot{R} = k_2 P\)

\(B + P + R = 1\)

<<<<<<< HEAD

However, I’m not sure if this is exacly the model I use in the simulation. In the simulation, we assumed that P->R transition can happen only after the BB->P transition.

=======

However, I’m not sure if this is exactly the model I use in the simulation. In the simulation, we assumed that P->R transition can happen only after the B->P transition.

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba

Because proportions and their derivatives are observed, we can find the rates:

\(k_1 = - \frac{\dot{B}}{B}\)

\(k_2 = \frac{\dot{R}}{P}\)

This will require a lot of smoothing, otherwise the derivatives will be all over the place.

First, I see if I can recover rates from the generated data.

<<<<<<< HEAD =======
timeDeriv <- function(chr, k=20) {
  ts <- list()
  for(col in chr$colours) {
    x <- chr$cnt[[col]] / chr$cnt$total
    x <- caTools::runmean(x, k)
    x <- ts(x, start=chr$timepars$start, deltat=chr$timepars$step)
    xdot <- diff(x)
    ts[[col]] <- x
    ts[[paste0(col, ".diff")]] <- xdot
  }
  ts
}
plotRates <- function(chr, k=20) {
  ts <- timeDeriv(chr, k=k)
  k1 <- -ts$B.diff / ts$B
  k2 <- ts$R.diff / ts$P
  k1[which(is.nan(k1))] <- NA
  k2[which(is.nan(k2))] <- NA
  df <- data.frame(t=time(k1), k1=k1, k2=k2)
  m <- melt(df, measure.vars = c("k1", "k2"))
  m$value <- as.numeric(m$value)
  m$value[which(m$value > 0.5)] <- 0.5
  m$value[which(m$value < -0.5)] <- -0.5
  ggplot(m, aes(x=t, y=value)) + geom_line(aes(colour=variable)) 
}

Start with a model with 10,000 cells and 0.1 min time step. In this model \(k_1 = 0.04\) and \(k_2 = 0\). Top panels show original data, lower panels - smoothed data.

grid.arrange(plotTimelines(tchr), plotRates(tchr, k=1), ncol=2)

grid.arrange(plotTimelines(tchr, smooth=TRUE, k=200), plotRates(tchr, k=200), ncol=2)

What happens if I use only 100 cells and 1 min time step in the model? This time \(k_2 = 0.04\).

chr <- generateCells(chr, nsim=100)
grid.arrange(plotTimelines(chr, k=1), plotRates(chr, k=1), ncol=2)

grid.arrange(plotTimelines(chr, smooth=TRUE, k=20), plotRates(chr, k=20), ncol=2)

And now, for real data. Here are scramble data smoothed with running mean with window size of 10 time points.

grid.arrange(plotTimelines(echr, smooth=TRUE, k=10), plotRates(echr, k=10), ncol=2)

Now, smoothing with 80 points.

grid.arrange(plotTimelines(echr, smooth=TRUE, k=80), plotRates(echr, k=80), ncol=2)

25/07/2017

Had a chat with Tomo and John yesterday. They wanted to add a score showing how far the model is from the experimental data. I did it by calculating \(\chi^2\) summed over all three curves. It is now added to the figure in the shiny app.

The next thing is to add transition P->B, with rate \(k_3\). It can happen only after time \(\Delta t_3\).

I added a simulation method (step-by-step). Now testing it.

pars <- c3pars(
  t1 = -30,
  k1 = 0.04,
  k2 = 0.04,
  k3 = 0.04,
  dt2 = 10,
  dt3 = 50
)
chr <- ChromCom3(pars)
chr <- generateCells(chr, nsim=1000, method="simulation")
plotTimelines(chr)

26/07/2017

What about fitting model to the data? “nlm” doesn’t work because model is stochastic. Method “SANN” from optim (that is stochastic simulated annealing) took very long time and went into a false minimum (negative \(k_2\)), as parameters cannot be constrained.

Finally I used “L-BFGS-B” method which allows box constraints. Alas, this method is not very good at finding the real minimum, often ending up in a local one. I’m guessing this is because of my stochastic model. Therefore, I need to run it several times and search for the best minimum. Using “mclapply” to speed it up.

I also changed the error score. \(\chi^2\) doesn’t work very well when expected counts are zero. And I cannot simply exclude them, because zero is an important number. Instead I calculate a simple RMS.

pars <- c3pars()
chr <- cacheData("fit_scramble_n3000_3par", fitChr, echr, pars, npar=3, nsim=3000, ntry=16, binDir=binDir)
plotTimelines(chr, expdata = echr, withpars=TRUE)

Now, the same, but with extra parameter, \(\Delta t_2\).

pars <- c3pars(dt2=5)
chr <- cacheData("fit_scramble_n3000_4par", fitChr, echr, pars, npar=4, nsim=3000, ntry=16, binDir=binDir)
plotTimelines(chr, expdata = echr, withpars=TRUE)

And now the other two data sets.

echr2 <- experimentalData(dataFile$NCAPD2)
pars <- c3pars()
chr2 <- cacheData("fit_NCAPD2_n3000_3par", fitChr, echr2, pars, npar=3, nsim=3000, ntry=16, ncores=8, binDir=binDir)
plotTimelines(chr2, expdata = echr2, withpars=TRUE)

pars <- c3pars(dt2=10)
chr2 <- cacheData("fit_NCAPD2_n3000_4par", fitChr, echr2, pars, npar=4, nsim=3000, ntry=16, ncores=8, binDir=binDir)
plotTimelines(chr2, expdata = echr2, withpars=TRUE)
echr3 <- experimentalData(dataFile$NCAPD3)
pars <- c3pars()
chr3 <- cacheData("fit_NCAPD3_n3000_3par", fitChr, echr3, pars, npar=3, nsim=3000, ntry=16, ncores=8, binDir=binDir)
plotTimelines(chr3, expdata = echr3, withpars=TRUE)

pars <- c3pars(dt2=10)
chr3 <- cacheData("fit_NCAPD3_n3000_4par", fitChr, echr3, pars, npar=4, nsim=3000, ntry=16, ncores=8, binDir=binDir)
plotTimelines(chr3, expdata = echr3, withpars=TRUE)

>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba
timeDeriv <- function(chr, k=20) {
  ts <- list()
  for(col in chr$colours) {
    x <- chr$cnt[[col]] / chr$cnt$total
    x <- caTools::runmean(x, k)
    x <- ts(x, start=chr$timepars$start, deltat=chr$timepars$step)
    xdot <- diff(x)
    ts[[col]] <- x
    ts[[paste0(col, ".diff")]] <- xdot
  }
  ts
}
plotRates <- function(chr, k=20) {
  ts <- timeDeriv(chr, k=k)
  k1 <- -ts$BB.diff / ts$BB
  k2 <- ts$R.diff / ts$P
  k1[which(is.nan(k1))] <- NA
  k2[which(is.nan(k2))] <- NA
  df <- data.frame(t=time(k1), k1=k1, k2=k2)
  m <- melt(df, measure.vars = c("k1", "k2"))
  m$value <- as.numeric(m$value)
  m$value[which(m$value > 0.5)] <- 0.5
  m$value[which(m$value < -0.5)] <- -0.5
  ggplot(m, aes(x=t, y=value)) + geom_line(aes(colour=variable)) 
}

Start with a model wiht 10,000 cells and 0.1 min time step. In this model \(k_1 = 0.04\) and \(k_2 = 0\). Top panels show original data, lower panels - smoothed data.

grid.arrange(plotTimelines(tchr), plotRates(tchr, k=1), ncol=2)

grid.arrange(plotTimelines(tchr, smooth=TRUE, k=200), plotRates(tchr, k=200), ncol=2)

What happens if I use only 100 cells and 1 min time step in the model? This time \(k_2 = 0.04\).

chr <- generateCells(chr, nsim=100)
grid.arrange(plotTimelines(chr, k=1), plotRates(chr, k=1), ncol=2)

grid.arrange(plotTimelines(chr, smooth=TRUE, k=20), plotRates(chr, k=20), ncol=2)

And now, for real data. Here are scramble data smoothed with running mean with window size of 10 time points.

grid.arrange(plotTimelines(echr, smooth=TRUE, k=10), plotRates(echr, k=10), ncol=2)

Now, smoothing with 80 points.

grid.arrange(plotTimelines(echr, smooth=TRUE, k=80), plotRates(echr, k=80), ncol=2)

<<<<<<< HEAD
LS0tCnRpdGxlOiAiQ2hyb21vc29tZSBjb21wYWN0aW9uIC0gc2ltcGxlIHRocmVlLXN0YXRlIG1vZGVsIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IGZhbHNlCiAgICB0b2NfZmxvYXQ6IGZhbHNlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgpgYGB7cn0KbGlicmFyeShDaHJvbUNvbSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShyZXNoYXBlMikKYGBgCgojIyAxMS8wNy8yMDE3CgpXcml0aW5nIGludHJvZHVjdGlvbi4gRmlyc3Qgc2NyaXB0IHRvIGRvIHNpbXVsYXRpb24uCgoKIyMgMTIvMDcvMjAxNwoKTGV0J3MgdHJ5IGlmIGl0IHdvcmtzLiBBbiBleGFtcGxlIGZvciAkdF8xID0gLTYwJCBtaW4sICRcRGVsdGEgdCA9IDAkLCAka18xID0gMC4wNFwge1xybSBtaW59XnstMX0kIGFuZCAka18yID0gMC4wNFwge1xybSBtaW59XnstMX0kLgoKYGBge3IsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTN9CnBhcnMgPC0gbGlzdCgKICB0MSA9IC02MCwKICBkdCA9IDAsCiAgcjEgPSAwLjA0LAogIHIyID0gMC4wNAopCmNociA8LSBDaHJvbUNvbTMocGFycykKY2hyIDwtIGdlbmVyYXRlQ2VsbHMoY2hyLCBuc2ltPTEwMDApCnBsb3RUaW1lbGluZXMoY2hyKQpgYGAKCkp1c3QgdG8gY2hlY2sgaWYgb3V0cHV0IGlzIGFzIGV4cGVjdGVkLiBXaXRoICRrXzI9MCQgd2Ugc2hvdWxkIGhhdmUgcHVyZSBleHBvbmVudGlhbCBkZWNheS4gVGhlIHllbGxvdyBjdXJ2ZSBpcyAkZV57LWtfMSB0fSQuCgpgYGB7ciwgZmlnLndpZHRoPTV9CnBhcnMgPC0gbGlzdCgKICB0MSA9IC02MCwKICBkdCA9IDAsCiAgcjEgPSAwLjA0LAogIHIyID0gMAopCnRjaHIgPC0gQ2hyb21Db20zKHBhcnMpCnRjaHIgPC0gZ2VuZXJhdGVDZWxscyh0Y2hyLCBuc2ltPTEwMDApCgp4IDwtIHNlcShmcm9tPXBhcnMkdDEsIHRvPTEwMCwgYnk9MSkKeSA8LSBleHAoLXBhcnMkcjEgKiAoeCAtIHBhcnMkdDEpKQpnIDwtIHBsb3RUaW1lbGluZXModGNocikKZyArIGdlb21fbGluZShkYXRhPWRhdGEuZnJhbWUoeD14LCB5PXkpLCBhZXMoeCx5KSwgY29sb3VyPSJ5ZWxsb3ciKQpgYGAKCkNsb3NlLCBidXQgbm90IHBlcmZlY3QuIEhlcmUgaXMgYW4gZXhhbXBsZSB3aXRoIG11Y2ggc21hbGxlciB0aW1lIHN0ZXAgKDAuMSkgYW5kIGxhcmdlciBudW1iZXIgb2YgY2VsbHMgKDEwLDAwMCkuCgpgYGB7ciwgZmlnLndpZHRoPTV9CnBhcnMgPC0gbGlzdCgKICB0MSA9IC02MCwKICBkdCA9IDAsCiAgcjEgPSAwLjA0LAogIHIyID0gMAopCnRjaHIgPC0gQ2hyb21Db20zKHBhcnMsIHRpbWUgPSBzZXEoZnJvbT0tMTQwLCB0bz05MCwgYnk9MC4xKSkKdGNociA8LSBnZW5lcmF0ZUNlbGxzKHRjaHIsIG5zaW09MTAwMDApCgp4IDwtIHNlcShmcm9tPXBhcnMkdDEsIHRvPTEwMCwgYnk9MSkKeSA8LSBleHAoLXBhcnMkcjEgKiAoeCAtIHBhcnMkdDEpKQpnIDwtIHBsb3RUaW1lbGluZXModGNocikKZyArIGdlb21fbGluZShkYXRhPWRhdGEuZnJhbWUoeD14LCB5PXkpLCBhZXMoeCx5KSwgY29sb3VyPSJ5ZWxsb3ciKQpgYGAKCgoKIyMjIFBhcmFtZXRlciBncmlkCgpgYGB7cn0KcGFyYW1ldGVyR3JpZCA8LSBmdW5jdGlvbihwYXJzLCBwYXIxLCByYW5nZTEsIHBhcjIsIHJhbmdlMikgewogIG1lbHRzIDwtIE5VTEwKICBmb3IocDEgaW4gcmFuZ2UxKSB7CiAgICBwYXJzW1twYXIxXV0gPC0gcDEKICAgIGZvcihwMiBpbiByYW5nZTIpIHsKICAgICAgcGFyc1tbcGFyMl1dIDwtIHAyCiAgICAgIGNociA8LSBDaHJvbUNvbTMocGFycykKICAgICAgY2hyIDwtIGdlbmVyYXRlQ2VsbHMoY2hyKQogICAgICBsYWJlbDEgPC0gc3ByaW50ZigiJXMgPSAlLjNnIiwgcGFyMSwgcDEpCiAgICAgIGxhYmVsMiA8LSBzcHJpbnRmKCIlcyA9ICUuM2ciLCBwYXIyLCBwMikKICAgICAgbSA8LSBtZWx0VGltZWxpbmVzKGNociwgbGFiZWwxPWxhYmVsMSwgbGFiZWwyPWxhYmVsMikKICAgICAgbWVsdHMgPC0gcmJpbmQobWVsdHMsIG0pCiAgICB9CiAgfQogIHRpbWVsaW5lUGFuZWwobWVsdHMpCn0KYGBgCgpgYGB7cn0KcGFycyA8LSBsaXN0KAogIHQxID0gLTMwLAogIGR0ID0gMCwKICByMSA9IDAuMDUsCiAgcjIgPSAwLjAxCikKCnJhbmdlMSA8LSBjKDAuMDEsIDAuMDUsIDAuMDgsIDAuMTIpCnJhbmdlMiA8LSBjKDAuMDEsIDAuMDUsIDAuMDgsIDAuMTIpCnBhcmFtZXRlckdyaWQocGFycywgInIxIiwgcmFuZ2UxLCAicjIiLCByYW5nZTIpCmBgYAogSSB0aGluayB3ZSBuZWVkIHRvIGludHJvZHVjZSBhIGRlbGF5IGJldHdlZW4gcGluayBhbmQgcmVkLgogCiAKYGBge3J9CnBhcnMgPC0gbGlzdCgKICB0MSA9IC0zMCwKICBkdCA9IDEwLAogIHIxID0gMC4wNSwKICByMiA9IDAuMDEKKQoKcmFuZ2UxIDwtIGMoMC4wMSwgMC4wMywgMC4wNSwgMC4xMCkKcmFuZ2UyIDwtIGMoMC4wMSwgMC4wNSwgMC4wOCwgMC4xMikKcGFyYW1ldGVyR3JpZChwYXJzLCAicjEiLCByYW5nZTEsICJyMiIsIHJhbmdlMikKYGBgCgpXaGF0IGFib3V0IHJhbmdlIG9mIGRlbGF5cz8KCmBgYHtyfQpwYXJzIDwtIGxpc3QoCiAgdDEgPSAtMzAsCiAgZHQgPSAwLAogIHIxID0gMC4wMywKICByMiA9IDAuMDEKKQoKcmFuZ2UxIDwtIGMoMCwgMTAsIDIwLCAzMCkKcmFuZ2UyIDwtIGMoMC4wMSwgMC4wNSwgMC4wOCwgMC4xMikKcGFyYW1ldGVyR3JpZChwYXJzLCAiZHQiLCByYW5nZTEsICJyMiIsIHJhbmdlMikKYGBgCgpFeHBlcmltZW50YWwgZGF0YS4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9NX0KZWNociA8LSBleHBlcmltZW50YWxEYXRhKGRhdGFGaWxlJHNjcmFtYmxlKQpwbG90VGltZWxpbmVzKGVjaHIsIHNtb290aD1UUlVFLCBrPTE1KQpgYGAKCgojIyAxMy8wNy8yMDE3CgpQcmVwYXJlZCBbc2hpbnkgYXBwXShodHRwczovL3NoaW55LmNvbXBiaW8uZHVuZGVlLmFjLnVrL21hcmVrX2Nocm9tY29tL3BhcmFtX3R1bmVyLykgZm9yIGRlcGxveW1lbnQuCgojIyAyNC8wNy8yMDE3CgpUb21vIHN1Z2dlc3RlZCB0aGF0IHRoZSBtb2RlbCBwYXJhbWV0ZXJzIGNhbiBiZSBkZXJpdmVkIGRpcmVjdGx5IGZyb20gZGF0YS4gV2UgY2FuIHdyaXRlIHRoZSBmb2xsb3dpbmcgZXF1YXRpb25zCgokXGRvdHtCfSA9IC1rXzEgQiQKCiRcZG90e1B9ID0ga18xIEIgLSBrXzIgUiQKCiRcZG90e1J9ID0ga18yIFAkCgokQiArIFAgKyBSID0gMSQKCkhvd2V2ZXIsIEknbSBub3Qgc3VyZSBpZiB0aGlzIGlzIGV4YWNseSB0aGUgbW9kZWwgSSB1c2UgaW4gdGhlIHNpbXVsYXRpb24uIEluIHRoZSBzaW11bGF0aW9uLCB3ZSBhc3N1bWVkIHRoYXQgUC0+UiB0cmFuc2l0aW9uIGNhbiBoYXBwZW4gb25seSBhZnRlciB0aGUgQkItPlAgdHJhbnNpdGlvbi4gCgpCZWNhdXNlIHByb3BvcnRpb25zIGFuZCB0aGVpciBkZXJpdmF0aXZlcyBhcmUgb2JzZXJ2ZWQsIHdlIGNhbiBmaW5kIHRoZSByYXRlczoKCiRrXzEgPSAtIFxmcmFje1xkb3R7Qn19e0J9JAoKJGtfMiA9IFxmcmFje1xkb3R7Un19e1B9JAoKVGhpcyB3aWxsIHJlcXVpcmUgYSBsb3Qgb2Ygc21vb3RoaW5nLCBvdGhlcndpc2UgdGhlIGRlcml2YXRpdmVzIHdpbGwgYmUgYWxsIG92ZXIgdGhlIHBsYWNlLgoKRmlyc3QsIEkgc2VlIGlmIEkgY2FuIHJlY292ZXIgcmF0ZXMgZnJvbSB0aGUgZ2VuZXJhdGVkIGRhdGEuCgpgYGB7cn0KdGltZURlcml2IDwtIGZ1bmN0aW9uKGNociwgaz0yMCkgewogIHRzIDwtIGxpc3QoKQogIGZvcihjb2wgaW4gY2hyJGNvbG91cnMpIHsKICAgIHggPC0gY2hyJGNudFtbY29sXV0gLyBjaHIkY250JHRvdGFsCiAgICB4IDwtIGNhVG9vbHM6OnJ1bm1lYW4oeCwgaykKICAgIHggPC0gdHMoeCwgc3RhcnQ9Y2hyJHRpbWVwYXJzJHN0YXJ0LCBkZWx0YXQ9Y2hyJHRpbWVwYXJzJHN0ZXApCiAgICB4ZG90IDwtIGRpZmYoeCkKICAgIHRzW1tjb2xdXSA8LSB4CiAgICB0c1tbcGFzdGUwKGNvbCwgIi5kaWZmIildXSA8LSB4ZG90CiAgfQogIHRzCn0KYGBgCgpgYGB7cn0KcGxvdFJhdGVzIDwtIGZ1bmN0aW9uKGNociwgaz0yMCkgewogIHRzIDwtIHRpbWVEZXJpdihjaHIsIGs9aykKICBrMSA8LSAtdHMkQkIuZGlmZiAvIHRzJEJCCiAgazIgPC0gdHMkUi5kaWZmIC8gdHMkUAogIGsxW3doaWNoKGlzLm5hbihrMSkpXSA8LSBOQQogIGsyW3doaWNoKGlzLm5hbihrMikpXSA8LSBOQQogIGRmIDwtIGRhdGEuZnJhbWUodD10aW1lKGsxKSwgazE9azEsIGsyPWsyKQogIG0gPC0gbWVsdChkZiwgbWVhc3VyZS52YXJzID0gYygiazEiLCAiazIiKSkKICBtJHZhbHVlIDwtIGFzLm51bWVyaWMobSR2YWx1ZSkKICBtJHZhbHVlW3doaWNoKG0kdmFsdWUgPiAwLjUpXSA8LSAwLjUKICBtJHZhbHVlW3doaWNoKG0kdmFsdWUgPCAtMC41KV0gPC0gLTAuNQogIGdncGxvdChtLCBhZXMoeD10LCB5PXZhbHVlKSkgKyBnZW9tX2xpbmUoYWVzKGNvbG91cj12YXJpYWJsZSkpIAp9CmBgYAoKU3RhcnQgd2l0aCBhIG1vZGVsIHdpaHQgMTAsMDAwIGNlbGxzIGFuZCAwLjEgbWluIHRpbWUgc3RlcC4gSW4gdGhpcyBtb2RlbCAka18xID0gMC4wNCQgYW5kICRrXzIgPSAwJC4gIFRvcCBwYW5lbHMgc2hvdyBvcmlnaW5hbCBkYXRhLCBsb3dlciBwYW5lbHMgLSBzbW9vdGhlZCBkYXRhLgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTN9CmdyaWQuYXJyYW5nZShwbG90VGltZWxpbmVzKHRjaHIpLCBwbG90UmF0ZXModGNociwgaz0xKSwgbmNvbD0yKQpncmlkLmFycmFuZ2UocGxvdFRpbWVsaW5lcyh0Y2hyLCBzbW9vdGg9VFJVRSwgaz0yMDApLCBwbG90UmF0ZXModGNociwgaz0yMDApLCBuY29sPTIpCmBgYAoKCldoYXQgaGFwcGVucyBpZiBJIHVzZSBvbmx5IDEwMCBjZWxscyBhbmQgMSBtaW4gdGltZSBzdGVwIGluIHRoZSBtb2RlbD8gVGhpcyB0aW1lICRrXzIgPSAwLjA0JC4KCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD0zfQpjaHIgPC0gZ2VuZXJhdGVDZWxscyhjaHIsIG5zaW09MTAwKQpncmlkLmFycmFuZ2UocGxvdFRpbWVsaW5lcyhjaHIsIGs9MSksIHBsb3RSYXRlcyhjaHIsIGs9MSksIG5jb2w9MikKZ3JpZC5hcnJhbmdlKHBsb3RUaW1lbGluZXMoY2hyLCBzbW9vdGg9VFJVRSwgaz0yMCksIHBsb3RSYXRlcyhjaHIsIGs9MjApLCBuY29sPTIpCmBgYAoKCkFuZCBub3csIGZvciByZWFsIGRhdGEuIEhlcmUgYXJlIHNjcmFtYmxlIGRhdGEgc21vb3RoZWQgd2l0aCBydW5uaW5nIG1lYW4gd2l0aCB3aW5kb3cgc2l6ZSBvZiAxMCB0aW1lIHBvaW50cy4KCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD0zfQpncmlkLmFycmFuZ2UocGxvdFRpbWVsaW5lcyhlY2hyLCBzbW9vdGg9VFJVRSwgaz0xMCksIHBsb3RSYXRlcyhlY2hyLCBrPTEwKSwgbmNvbD0yKQpgYGAKCk5vdywgc21vb3RoaW5nIHdpdGggODAgcG9pbnRzLgoKYGBge3IsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTN9CmdyaWQuYXJyYW5nZShwbG90VGltZWxpbmVzKGVjaHIsIHNtb290aD1UUlVFLCBrPTgwKSwgcGxvdFJhdGVzKGVjaHIsIGs9ODApLCBuY29sPTIpCmBgYAo=
=======
LS0tCnRpdGxlOiAiQ2hyb21vc29tZSBjb21wYWN0aW9uIC0gc2ltcGxlIHRocmVlLXN0YXRlIG1vZGVsIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IGZhbHNlCiAgICB0b2NfZmxvYXQ6IGZhbHNlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgpgYGB7cn0KbGlicmFyeShteWxpYikKbGlicmFyeShDaHJvbUNvbSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShwYXJhbGxlbCkKCmJpbkRpciA8LSAiLi4vUkRhdGEiCmBgYAoKIyMgMTEvMDcvMjAxNwoKV3JpdGluZyBpbnRyb2R1Y3Rpb24uIEZpcnN0IHNjcmlwdCB0byBkbyBzaW11bGF0aW9uLgoKCiMjIDEyLzA3LzIwMTcKCkxldCdzIHRyeSBpZiBpdCB3b3Jrcy4gQW4gZXhhbXBsZSBmb3IgJHRfMSA9IC02MCQgbWluLCAkXERlbHRhIHQgPSAwJCwgJGtfMSA9IDAuMDRcIHtccm0gbWlufV57LTF9JCBhbmQgJGtfMiA9IDAuMDRcIHtccm0gbWlufV57LTF9JC4KCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0zfQpwYXJzIDwtIGMzcGFycygKICB0MSA9IC02MCwKICBkdDIgPSAwLAogIGsxID0gMC4wNCwKICBrMiA9IDAuMDQKKQpjaHIgPC0gQ2hyb21Db20zKHBhcnMpCmNociA8LSBnZW5lcmF0ZUNlbGxzKGNociwgbnNpbT0xMDAwKQpwbG90VGltZWxpbmVzKGNocikKYGBgCgpKdXN0IHRvIGNoZWNrIGlmIG91dHB1dCBpcyBhcyBleHBlY3RlZC4gV2l0aCAka18yPTAkIHdlIHNob3VsZCBoYXZlIHB1cmUgZXhwb25lbnRpYWwgZGVjYXkuIFRoZSB5ZWxsb3cgY3VydmUgaXMgJGVeey1rXzEgdH0kLgoKYGBge3IsIGZpZy53aWR0aD01fQpwYXJzIDwtIGMzcGFycygKICB0MSA9IC02MCwKICBkdDIgPSAwLAogIGsxID0gMC4wNCwKICBrMiA9IDAKKQp0Y2hyIDwtIENocm9tQ29tMyhwYXJzKQp0Y2hyIDwtIGdlbmVyYXRlQ2VsbHModGNociwgbnNpbT0xMDAwKQoKeCA8LSBzZXEoZnJvbT1wYXJzJHQxLCB0bz0xMDAsIGJ5PTEpCnkgPC0gZXhwKC1wYXJzJGsxICogKHggLSBwYXJzJHQxKSkKZyA8LSBwbG90VGltZWxpbmVzKHRjaHIpCmcgKyBnZW9tX2xpbmUoZGF0YT1kYXRhLmZyYW1lKHg9eCwgeT15KSwgYWVzKHgseSksIGNvbG91cj0ieWVsbG93IikKYGBgCgpDbG9zZSwgYnV0IG5vdCBwZXJmZWN0LiBIZXJlIGlzIGFuIGV4YW1wbGUgd2l0aCBtdWNoIHNtYWxsZXIgdGltZSBzdGVwICgwLjEpIGFuZCBsYXJnZXIgbnVtYmVyIG9mIGNlbGxzICgxMCwwMDApLgoKYGBge3IsIGZpZy53aWR0aD01fQpwYXJzIDwtIGMzcGFycygKICB0MSA9IC02MCwKICBkdDIgPSAwLAogIGsxID0gMC4wNCwKICBrMiA9IDAKKQp0Y2hyIDwtIENocm9tQ29tMyhwYXJzLCB0aW1lID0gc2VxKGZyb209LTE0MCwgdG89OTAsIGJ5PTAuMSkpCnRjaHIgPC0gZ2VuZXJhdGVDZWxscyh0Y2hyLCBuc2ltPTEwMDAwKQoKeCA8LSBzZXEoZnJvbT1wYXJzJHQxLCB0bz0xMDAsIGJ5PTEpCnkgPC0gZXhwKC1wYXJzJGsxICogKHggLSBwYXJzJHQxKSkKZyA8LSBwbG90VGltZWxpbmVzKHRjaHIpCmcgKyBnZW9tX2xpbmUoZGF0YT1kYXRhLmZyYW1lKHg9eCwgeT15KSwgYWVzKHgseSksIGNvbG91cj0ieWVsbG93IikKYGBgCgoKCiMjIyBQYXJhbWV0ZXIgZ3JpZAoKYGBge3J9CnBhcmFtZXRlckdyaWQgPC0gZnVuY3Rpb24ocGFycywgcGFyMSwgcmFuZ2UxLCBwYXIyLCByYW5nZTIpIHsKICBtZWx0cyA8LSBOVUxMCiAgZm9yKHAxIGluIHJhbmdlMSkgewogICAgcGFyc1tbcGFyMV1dIDwtIHAxCiAgICBmb3IocDIgaW4gcmFuZ2UyKSB7CiAgICAgIHBhcnNbW3BhcjJdXSA8LSBwMgogICAgICBjaHIgPC0gQ2hyb21Db20zKHBhcnMpCiAgICAgIGNociA8LSBnZW5lcmF0ZUNlbGxzKGNocikKICAgICAgbGFiZWwxIDwtIHNwcmludGYoIiVzID0gJS4zZyIsIHBhcjEsIHAxKQogICAgICBsYWJlbDIgPC0gc3ByaW50ZigiJXMgPSAlLjNnIiwgcGFyMiwgcDIpCiAgICAgIG0gPC0gbWVsdFRpbWVsaW5lcyhjaHIsIGxhYmVsMT1sYWJlbDEsIGxhYmVsMj1sYWJlbDIpCiAgICAgIG1lbHRzIDwtIHJiaW5kKG1lbHRzLCBtKQogICAgfQogIH0KICB0aW1lbGluZVBhbmVsKG1lbHRzKQp9CmBgYAoKYGBge3J9CnBhcnMgPC0gYzNwYXJzKAogIHQxID0gLTMwLAogIGR0MiA9IDAsCiAgazEgPSAwLjA1LAogIGsyID0gMC4wMQopCgpyYW5nZTEgPC0gYygwLjAxLCAwLjA1LCAwLjA4LCAwLjEyKQpyYW5nZTIgPC0gYygwLjAxLCAwLjA1LCAwLjA4LCAwLjEyKQpwYXJhbWV0ZXJHcmlkKHBhcnMsICJrMSIsIHJhbmdlMSwgImsyIiwgcmFuZ2UyKQpgYGAKIEkgdGhpbmsgd2UgbmVlZCB0byBpbnRyb2R1Y2UgYSBkZWxheSBiZXR3ZWVuIHBpbmsgYW5kIHJlZC4KIAogCmBgYHtyfQpwYXJzIDwtIGMzcGFycygKICB0MSA9IC0zMCwKICBkdDIgPSAxMCwKICBrMSA9IDAuMDUsCiAgazIgPSAwLjAxCikKCnJhbmdlMSA8LSBjKDAuMDEsIDAuMDMsIDAuMDUsIDAuMTApCnJhbmdlMiA8LSBjKDAuMDEsIDAuMDUsIDAuMDgsIDAuMTIpCnBhcmFtZXRlckdyaWQocGFycywgImsxIiwgcmFuZ2UxLCAiazIiLCByYW5nZTIpCmBgYAoKV2hhdCBhYm91dCByYW5nZSBvZiBkZWxheXM/CgpgYGB7cn0KcGFycyA8LSBjM3BhcnMoCiAgdDEgPSAtMzAsCiAgZHQyID0gMCwKICBrMSA9IDAuMDMsCiAgazIgPSAwLjAxCikKCnJhbmdlMSA8LSBjKDAsIDEwLCAyMCwgMzApCnJhbmdlMiA8LSBjKDAuMDEsIDAuMDUsIDAuMDgsIDAuMTIpCnBhcmFtZXRlckdyaWQocGFycywgImR0IiwgcmFuZ2UxLCAiazIiLCByYW5nZTIpCmBgYAoKRXhwZXJpbWVudGFsIGRhdGEuCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTV9CmVjaHIgPC0gZXhwZXJpbWVudGFsRGF0YShkYXRhRmlsZSRzY3JhbWJsZSkKcGxvdFRpbWVsaW5lcyhlY2hyLCBzbW9vdGg9VFJVRSwgaz0xNSkKYGBgCgoKIyMgMTMvMDcvMjAxNwoKUHJlcGFyZWQgW3NoaW55IGFwcF0oaHR0cHM6Ly9zaGlueS5jb21wYmlvLmR1bmRlZS5hYy51ay9tYXJla19jaHJvbWNvbS9wYXJhbV90dW5lci8pIGZvciBkZXBsb3ltZW50LgoKIyMgMjQvMDcvMjAxNwoKVG9tbyBzdWdnZXN0ZWQgdGhhdCB0aGUgbW9kZWwgcGFyYW1ldGVycyBjYW4gYmUgZGVyaXZlZCBkaXJlY3RseSBmcm9tIGRhdGEuIFdlIGNhbiB3cml0ZSB0aGUgZm9sbG93aW5nIGVxdWF0aW9ucwoKJFxkb3R7Qn0gPSAta18xIEIkCgokXGRvdHtQfSA9IGtfMSBCIC0ga18yIFIkCgokXGRvdHtSfSA9IGtfMiBQJAoKJEIgKyBQICsgUiA9IDEkCgpIb3dldmVyLCBJJ20gbm90IHN1cmUgaWYgdGhpcyBpcyBleGFjdGx5IHRoZSBtb2RlbCBJIHVzZSBpbiB0aGUgc2ltdWxhdGlvbi4gSW4gdGhlIHNpbXVsYXRpb24sIHdlIGFzc3VtZWQgdGhhdCBQLT5SIHRyYW5zaXRpb24gY2FuIGhhcHBlbiBvbmx5IGFmdGVyIHRoZSBCLT5QIHRyYW5zaXRpb24uIAoKQmVjYXVzZSBwcm9wb3J0aW9ucyBhbmQgdGhlaXIgZGVyaXZhdGl2ZXMgYXJlIG9ic2VydmVkLCB3ZSBjYW4gZmluZCB0aGUgcmF0ZXM6Cgoka18xID0gLSBcZnJhY3tcZG90e0J9fXtCfSQKCiRrXzIgPSBcZnJhY3tcZG90e1J9fXtQfSQKClRoaXMgd2lsbCByZXF1aXJlIGEgbG90IG9mIHNtb290aGluZywgb3RoZXJ3aXNlIHRoZSBkZXJpdmF0aXZlcyB3aWxsIGJlIGFsbCBvdmVyIHRoZSBwbGFjZS4KCkZpcnN0LCBJIHNlZSBpZiBJIGNhbiByZWNvdmVyIHJhdGVzIGZyb20gdGhlIGdlbmVyYXRlZCBkYXRhLgoKYGBge3J9CnRpbWVEZXJpdiA8LSBmdW5jdGlvbihjaHIsIGs9MjApIHsKICB0cyA8LSBsaXN0KCkKICBmb3IoY29sIGluIGNociRjb2xvdXJzKSB7CiAgICB4IDwtIGNociRjbnRbW2NvbF1dIC8gY2hyJGNudCR0b3RhbAogICAgeCA8LSBjYVRvb2xzOjpydW5tZWFuKHgsIGspCiAgICB4IDwtIHRzKHgsIHN0YXJ0PWNociR0aW1lcGFycyRzdGFydCwgZGVsdGF0PWNociR0aW1lcGFycyRzdGVwKQogICAgeGRvdCA8LSBkaWZmKHgpCiAgICB0c1tbY29sXV0gPC0geAogICAgdHNbW3Bhc3RlMChjb2wsICIuZGlmZiIpXV0gPC0geGRvdAogIH0KICB0cwp9CmBgYAoKYGBge3J9CnBsb3RSYXRlcyA8LSBmdW5jdGlvbihjaHIsIGs9MjApIHsKICB0cyA8LSB0aW1lRGVyaXYoY2hyLCBrPWspCiAgazEgPC0gLXRzJEIuZGlmZiAvIHRzJEIKICBrMiA8LSB0cyRSLmRpZmYgLyB0cyRQCiAgazFbd2hpY2goaXMubmFuKGsxKSldIDwtIE5BCiAgazJbd2hpY2goaXMubmFuKGsyKSldIDwtIE5BCiAgZGYgPC0gZGF0YS5mcmFtZSh0PXRpbWUoazEpLCBrMT1rMSwgazI9azIpCiAgbSA8LSBtZWx0KGRmLCBtZWFzdXJlLnZhcnMgPSBjKCJrMSIsICJrMiIpKQogIG0kdmFsdWUgPC0gYXMubnVtZXJpYyhtJHZhbHVlKQogIG0kdmFsdWVbd2hpY2gobSR2YWx1ZSA+IDAuNSldIDwtIDAuNQogIG0kdmFsdWVbd2hpY2gobSR2YWx1ZSA8IC0wLjUpXSA8LSAtMC41CiAgZ2dwbG90KG0sIGFlcyh4PXQsIHk9dmFsdWUpKSArIGdlb21fbGluZShhZXMoY29sb3VyPXZhcmlhYmxlKSkgCn0KYGBgCgpTdGFydCB3aXRoIGEgbW9kZWwgd2l0aCAxMCwwMDAgY2VsbHMgYW5kIDAuMSBtaW4gdGltZSBzdGVwLiBJbiB0aGlzIG1vZGVsICRrXzEgPSAwLjA0JCBhbmQgJGtfMiA9IDAkLiAgVG9wIHBhbmVscyBzaG93IG9yaWdpbmFsIGRhdGEsIGxvd2VyIHBhbmVscyAtIHNtb290aGVkIGRhdGEuCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9M30KZ3JpZC5hcnJhbmdlKHBsb3RUaW1lbGluZXModGNociksIHBsb3RSYXRlcyh0Y2hyLCBrPTEpLCBuY29sPTIpCmdyaWQuYXJyYW5nZShwbG90VGltZWxpbmVzKHRjaHIsIHNtb290aD1UUlVFLCBrPTIwMCksIHBsb3RSYXRlcyh0Y2hyLCBrPTIwMCksIG5jb2w9MikKYGBgCgoKV2hhdCBoYXBwZW5zIGlmIEkgdXNlIG9ubHkgMTAwIGNlbGxzIGFuZCAxIG1pbiB0aW1lIHN0ZXAgaW4gdGhlIG1vZGVsPyBUaGlzIHRpbWUgJGtfMiA9IDAuMDQkLgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTN9CmNociA8LSBnZW5lcmF0ZUNlbGxzKGNociwgbnNpbT0xMDApCmdyaWQuYXJyYW5nZShwbG90VGltZWxpbmVzKGNociwgaz0xKSwgcGxvdFJhdGVzKGNociwgaz0xKSwgbmNvbD0yKQpncmlkLmFycmFuZ2UocGxvdFRpbWVsaW5lcyhjaHIsIHNtb290aD1UUlVFLCBrPTIwKSwgcGxvdFJhdGVzKGNociwgaz0yMCksIG5jb2w9MikKYGBgCgoKQW5kIG5vdywgZm9yIHJlYWwgZGF0YS4gSGVyZSBhcmUgc2NyYW1ibGUgZGF0YSBzbW9vdGhlZCB3aXRoIHJ1bm5pbmcgbWVhbiB3aXRoIHdpbmRvdyBzaXplIG9mIDEwIHRpbWUgcG9pbnRzLgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTN9CmdyaWQuYXJyYW5nZShwbG90VGltZWxpbmVzKGVjaHIsIHNtb290aD1UUlVFLCBrPTEwKSwgcGxvdFJhdGVzKGVjaHIsIGs9MTApLCBuY29sPTIpCmBgYAoKTm93LCBzbW9vdGhpbmcgd2l0aCA4MCBwb2ludHMuCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9M30KZ3JpZC5hcnJhbmdlKHBsb3RUaW1lbGluZXMoZWNociwgc21vb3RoPVRSVUUsIGs9ODApLCBwbG90UmF0ZXMoZWNociwgaz04MCksIG5jb2w9MikKYGBgCgojIyAyNS8wNy8yMDE3CgpIYWQgYSBjaGF0IHdpdGggVG9tbyBhbmQgSm9obiB5ZXN0ZXJkYXkuIFRoZXkgd2FudGVkIHRvIGFkZCBhIHNjb3JlIHNob3dpbmcgaG93IGZhciB0aGUgbW9kZWwgaXMgZnJvbSB0aGUgZXhwZXJpbWVudGFsIGRhdGEuIEkgZGlkIGl0IGJ5IGNhbGN1bGF0aW5nICRcY2hpXjIkIHN1bW1lZCBvdmVyIGFsbCB0aHJlZSBjdXJ2ZXMuIEl0IGlzIG5vdyBhZGRlZCB0byB0aGUgZmlndXJlIGluIHRoZSBzaGlueSBhcHAuCgpUaGUgbmV4dCB0aGluZyBpcyB0byBhZGQgdHJhbnNpdGlvbiBQLT5CLCB3aXRoIHJhdGUgJGtfMyQuIEl0IGNhbiBoYXBwZW4gb25seSBhZnRlciB0aW1lICRcRGVsdGEgdF8zJC4KCkkgYWRkZWQgYSBzaW11bGF0aW9uIG1ldGhvZCAoc3RlcC1ieS1zdGVwKS4gTm93IHRlc3RpbmcgaXQuCgpgYGB7ciwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9M30KcGFycyA8LSBjM3BhcnMoCiAgdDEgPSAtMzAsCiAgazEgPSAwLjA0LAogIGsyID0gMC4wNCwKICBrMyA9IDAuMDQsCiAgZHQyID0gMTAsCiAgZHQzID0gNTAKKQpjaHIgPC0gQ2hyb21Db20zKHBhcnMpCmNociA8LSBnZW5lcmF0ZUNlbGxzKGNociwgbnNpbT0xMDAwLCBtZXRob2Q9InNpbXVsYXRpb24iKQpwbG90VGltZWxpbmVzKGNocikKYGBgCgojIyAyNi8wNy8yMDE3CgpXaGF0IGFib3V0IGZpdHRpbmcgbW9kZWwgdG8gdGhlIGRhdGE/ICJubG0iIGRvZXNuJ3Qgd29yayBiZWNhdXNlIG1vZGVsIGlzIHN0b2NoYXN0aWMuIE1ldGhvZCAiU0FOTiIgZnJvbSBvcHRpbSAodGhhdCBpcyBzdG9jaGFzdGljIHNpbXVsYXRlZCBhbm5lYWxpbmcpIHRvb2sgdmVyeSBsb25nIHRpbWUgYW5kIHdlbnQgaW50byBhIGZhbHNlIG1pbmltdW0gKG5lZ2F0aXZlICRrXzIkKSwgYXMgcGFyYW1ldGVycyBjYW5ub3QgYmUgY29uc3RyYWluZWQuCgpGaW5hbGx5IEkgdXNlZCAiTC1CRkdTLUIiIG1ldGhvZCB3aGljaCBhbGxvd3MgYm94IGNvbnN0cmFpbnRzLiBBbGFzLCB0aGlzIG1ldGhvZCBpcyBub3QgdmVyeSBnb29kIGF0IGZpbmRpbmcgdGhlIHJlYWwgbWluaW11bSwgb2Z0ZW4gZW5kaW5nIHVwIGluIGEgbG9jYWwgb25lLiBJJ20gZ3Vlc3NpbmcgdGhpcyBpcyBiZWNhdXNlIG9mIG15IHN0b2NoYXN0aWMgbW9kZWwuIFRoZXJlZm9yZSwgSSBuZWVkIHRvIHJ1biBpdCBzZXZlcmFsIHRpbWVzIGFuZCBzZWFyY2ggZm9yIHRoZSBiZXN0IG1pbmltdW0uIFVzaW5nICJtY2xhcHBseSIgdG8gc3BlZWQgaXQgdXAuCgpJIGFsc28gY2hhbmdlZCB0aGUgZXJyb3Igc2NvcmUuICRcY2hpXjIkIGRvZXNuJ3Qgd29yayB2ZXJ5IHdlbGwgd2hlbiBleHBlY3RlZCBjb3VudHMgYXJlIHplcm8uIEFuZCBJIGNhbm5vdCBzaW1wbHkgZXhjbHVkZSB0aGVtLCBiZWNhdXNlIHplcm8gaXMgYW4gaW1wb3J0YW50IG51bWJlci4gSW5zdGVhZCBJIGNhbGN1bGF0ZSBhIHNpbXBsZSBSTVMuCgpgYGB7ciwgZmlnLndpZHRoPTV9CnBhcnMgPC0gYzNwYXJzKCkKY2hyIDwtIGNhY2hlRGF0YSgiZml0X3NjcmFtYmxlX24zMDAwXzNwYXIiLCBmaXRDaHIsIGVjaHIsIHBhcnMsIG5wYXI9MywgbnNpbT0zMDAwLCBudHJ5PTE2LCBiaW5EaXI9YmluRGlyKQpwbG90VGltZWxpbmVzKGNociwgZXhwZGF0YSA9IGVjaHIsIHdpdGhwYXJzPVRSVUUpCmBgYAoKTm93LCB0aGUgc2FtZSwgYnV0IHdpdGggZXh0cmEgcGFyYW1ldGVyLCAkXERlbHRhIHRfMiQuCgpgYGB7ciwgZmlnLndpZHRoPTV9CnBhcnMgPC0gYzNwYXJzKGR0Mj01KQpjaHIgPC0gY2FjaGVEYXRhKCJmaXRfc2NyYW1ibGVfbjMwMDBfNHBhciIsIGZpdENociwgZWNociwgcGFycywgbnBhcj00LCBuc2ltPTMwMDAsIG50cnk9MTYsIGJpbkRpcj1iaW5EaXIpCnBsb3RUaW1lbGluZXMoY2hyLCBleHBkYXRhID0gZWNociwgd2l0aHBhcnM9VFJVRSkKYGBgCgpBbmQgbm93IHRoZSBvdGhlciB0d28gZGF0YSBzZXRzLgoKYGBge3IsIGZpZy53aWR0aD01fQplY2hyMiA8LSBleHBlcmltZW50YWxEYXRhKGRhdGFGaWxlJE5DQVBEMikKcGFycyA8LSBjM3BhcnMoKQpjaHIyIDwtIGNhY2hlRGF0YSgiZml0X05DQVBEMl9uMzAwMF8zcGFyIiwgZml0Q2hyLCBlY2hyMiwgcGFycywgbnBhcj0zLCBuc2ltPTMwMDAsIG50cnk9MTYsIG5jb3Jlcz04LCBiaW5EaXI9YmluRGlyKQpwbG90VGltZWxpbmVzKGNocjIsIGV4cGRhdGEgPSBlY2hyMiwgd2l0aHBhcnM9VFJVRSkKCnBhcnMgPC0gYzNwYXJzKGR0Mj0xMCkKY2hyMiA8LSBjYWNoZURhdGEoImZpdF9OQ0FQRDJfbjMwMDBfNHBhciIsIGZpdENociwgZWNocjIsIHBhcnMsIG5wYXI9NCwgbnNpbT0zMDAwLCBudHJ5PTE2LCBuY29yZXM9OCwgYmluRGlyPWJpbkRpcikKcGxvdFRpbWVsaW5lcyhjaHIyLCBleHBkYXRhID0gZWNocjIsIHdpdGhwYXJzPVRSVUUpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9NX0KZWNocjMgPC0gZXhwZXJpbWVudGFsRGF0YShkYXRhRmlsZSROQ0FQRDMpCnBhcnMgPC0gYzNwYXJzKCkKY2hyMyA8LSBjYWNoZURhdGEoImZpdF9OQ0FQRDNfbjMwMDBfM3BhciIsIGZpdENociwgZWNocjMsIHBhcnMsIG5wYXI9MywgbnNpbT0zMDAwLCBudHJ5PTE2LCBuY29yZXM9OCwgYmluRGlyPWJpbkRpcikKcGxvdFRpbWVsaW5lcyhjaHIzLCBleHBkYXRhID0gZWNocjMsIHdpdGhwYXJzPVRSVUUpCgpwYXJzIDwtIGMzcGFycyhkdDI9MTApCmNocjMgPC0gY2FjaGVEYXRhKCJmaXRfTkNBUEQzX24zMDAwXzRwYXIiLCBmaXRDaHIsIGVjaHIzLCBwYXJzLCBucGFyPTQsIG5zaW09MzAwMCwgbnRyeT0xNiwgbmNvcmVzPTgsIGJpbkRpcj1iaW5EaXIpCnBsb3RUaW1lbGluZXMoY2hyMywgZXhwZGF0YSA9IGVjaHIzLCB3aXRocGFycz1UUlVFKQpgYGAKCg==
>>>>>>> 01b0e8d10be96d37a253e2c8c213bf6e968042ba